// Function to rotate a set of photos.
// Copyright 2006 (C) Ralph Thomas

#include <apps/photo/rotate.h>
#include <apps/photo/photodb.h>
#include <datapumps/progress.h>
#include <util/db.h>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <boost/bind.hpp>
#include <jpeglib.h>
#include <jpeg/transupp.h>
#include <util/thread.h>
extern "C" {
#include <jpegtools.h>
#include <genthumbnail.h>
}
#include <string.h>

#define THUMB_MAX	65536

namespace apps {
	namespace photo {
		void rotate(const std::string& filename, unsigned int degrees, char* thumbnail, datapumps::progress_report_t* progress, unsigned int& count) {
			//
			// Report progress.
			//
			if (progress) progress->state_progress(count++, filename);

			degrees %= 360;
			//
			// The filename we've been given is a URL. Strip off the
			// file://.
			//
			std::string fn( filename.substr( 7 ) );
			//
			// Attempt to re-orient the image according to it's
			// EXIF orientation tag.
			//
			char* cfn( strdup( fn.c_str() ) );
			int flags( JFLAG_TRANSFORM_IMAGE | JFLAG_TRANSFORM_THUMBNAIL | JFLAG_UPDATE_ORIENTATION );
			int tsize = create_thumbnail( cfn, (unsigned char*) thumbnail, THUMB_MAX );
			JXFORM_CODE orientation(JXFORM_ROT_270);
			if (degrees == 90) orientation = JXFORM_ROT_90;
			else if (degrees == 180) orientation = JXFORM_ROT_180;
			jpeg_transform_inplace( cfn, orientation, NULL, thumbnail, tsize, flags );
			free( cfn );
		}
		void do_rotate_one(const std::string& url, unsigned int degrees) {
			char* thumbnail( new char [THUMB_MAX] );
			unsigned int c(0);
			rotate(url, degrees, thumbnail, 0, c);
			delete[] thumbnail;
		}
		void do_rotate(util::cow_vector<int>::type ids, unsigned int degrees) {
			util::db_ptr_t db(util::db::fromPath( getPhotoDatabasePath() ));
			datapumps::progress_report_t progress("Rotation Progress");
			//
			// Build the query.
			//
			std::stringstream ss;
			ss << "select filename from photos where id in (";
			std::copy(ids->begin(), ids->end(), std::ostream_iterator<int>(ss, ","));
			ss << ");";
			//
			// Perform the query.
			//
			adobe::dictionary_t results;
			db->query( ss.str(), results );
			//
			// Get the list of results and perform rotation.
			//
			char* thumbnail( new char [THUMB_MAX] );
			util::cow_vector<std::string>::type filenames( results.get<util::cow_vector<std::string>::type>( adobe::static_name_t( "filename" ) ) );
			progress.set_count(filenames->size());
			unsigned int count(0);
			std::for_each(filenames->begin(), filenames->end(), boost::bind( &rotate, _1, degrees, thumbnail, &progress, boost::ref(count) ));
			delete[] thumbnail;
		}
		static util::thread rotate_thread_s;
		void rotate(util::cow_vector<int>::type ids, unsigned int degrees) {
			rotate_thread_s.adoptWork( boost::bind( &do_rotate, ids, degrees ) );
		}
		void rotate_one(const std::string& url, unsigned int degrees) {
			rotate_thread_s.adoptWork( boost::bind( &do_rotate_one, url, degrees ) );
		}
	}
}

